package org.bultreebank.index.utils;

import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.bultreebank.search_engine.integration.SearchEngineImpl;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

import clark.dom.impl.DOMFactory;
import clark.dtd.dtdIO.DTDIOManager;
import clark.loader.DefaultFileFilter;
import clark.loader.Loader;
import clark.memory.DTDInfo;
import clark.memory.Memory;
import clark.xpath.MainXPath;
/**
 * Loads the configuration of classes that are specified for
 * usage in the config.xml file. The storage, indexing analyzer,
 * search analyzer, extractor implementations can be configured there.
 * @author Aneliya Ticheva
 *
 */
public class SystemInit implements Constants
{
	public static final String defStorageLocation = "DocumentRepository";
	private static final String storageLocation = "location";
	private static final String configElem = "config";
	private static final String storageElem = "storage";
	private static final String classNameAttr = "className";
	private static final String langAttr = "lang";
	private static final String indexAnalyzers = "indexAnalyzers";
	private static final String searchAnalyzers = "searchAnalyzers";
	private static final String analyzer = "analyzer";
	private static final String extractor = "extractor";
	public static final String storageDefaultClass = "org.bultreebank.document_repository.impl.StorageManipulationImpl";
	private static final String extractorDefaultClass = "org.bultreebank.extractor.RelevantContentExrtactor";
	private Document configDoc;
	private static SystemInit initManager;
	private String repositoryPath;
	public static SystemInit getInstance() throws Exception
	{	
		if (initManager == null)
			return new SystemInit();
		else
			return initManager;
	}
	public static SystemInit getInstance(String repositoryPath) throws Exception
	{	
		if (initManager == null)
			return new SystemInit(repositoryPath);
		else
			return initManager;
	}
	private SystemInit() throws Exception
	{
		repositoryPath = org.bultreebank.search_engine.SearchEngineImpl.repositoryPath;
		File configFile = new File(repositoryPath + CONFIG_DOC_PATH);
		if (configFile.exists())
		try
		{
			if (Validator.isConfigValid(repositoryPath))
				loadConfigDoc();
			else
				throw new Exception("The config file " + repositoryPath + CONFIG_DOC_PATH + " is not valid format!");
		}
		catch (Exception e)
		{
			throw new Exception("The config file " + repositoryPath + CONFIG_DOC_PATH + " is not valid format!");
		}
		else
			configDoc = createConfigDoc();
	}
	private SystemInit(String repositoryPath) throws Exception
	{
		this.repositoryPath = repositoryPath;
		File configFile = new File(repositoryPath + CONFIG_DOC_PATH);
		if (configFile.exists())
		try
		{
			if (Validator.isConfigValid(repositoryPath))
				loadConfigDoc();
			else
				throw new Exception("The config file " + repositoryPath + CONFIG_DOC_PATH + " is not valid format!");
		}
		catch (Exception e)
		{
			throw new Exception("The config file " + repositoryPath + CONFIG_DOC_PATH + " is not valid format!");
		}
		else
			configDoc = createConfigDoc();
	}
	
	public String getStorageClass()
	{
		String xpath = "//storage/@className";
		List<Node> storageNodes = MainXPath.processXPath(xpath, configDoc.getDocumentElement());
		return storageNodes.get(0).getNodeValue();
	}
	public String getStorageLocation()
	{
		String xpath = "//storage/@location";
		List<Node> storageNodes = MainXPath.processXPath(xpath, configDoc.getDocumentElement());
		return storageNodes.get(0).getNodeValue();
	}
	public String getExtractorClass()
	{
		String xpath = "//extractor/@className";
		List<Node> storageNodes = MainXPath.processXPath(xpath, configDoc.getDocumentElement());
		return storageNodes.get(0).getNodeValue();
	}
	public Map<String, String> getSearchLangMap()
	{
		String xpath = "//searchAnalyzers/analyzer";
		return getAnalyzersMap(xpath);
	}
	public Map<String, String> getIndexLangMap()
	{
		String xpath = "//indexAnalyzers/analyzer";
		return getAnalyzersMap(xpath);
	}
	private Map<String, String> getAnalyzersMap(String xpath)
	{
		Map<String, String> langMap = new HashMap<String, String>();
		List<Node> analyzersNodes = MainXPath.processXPath(xpath, configDoc.getDocumentElement());
		for (Node analyzer:analyzersNodes)
		{
			Element analyzerElem = (Element)analyzer;
			String lang = analyzerElem.getAttribute(langAttr);
			String className = analyzerElem.getAttribute(classNameAttr);
			langMap.put(lang, className);
		}
		return langMap;
	}
	private void loadConfigDoc() throws Exception
	{
		configDoc = Utils.getDocumentFromString(Utils.getStringRepresentationOfFileContent(repositoryPath + CONFIG_DOC_PATH));
	}
	private Document createConfigDoc() throws Exception
	{
		Document configDoc = DOMFactory.getEmptyDocument();
		Element config = configDoc.createElement(configElem);
		configDoc.appendChild(config);
		Element storage = configDoc.createElement(storageElem);
		storage.setAttribute(classNameAttr, storageDefaultClass);
		storage.setAttribute(storageLocation, "");
		config.appendChild(storage);
		
		Element extractor = configDoc.createElement(SystemInit.extractor);
		extractor.setAttribute(classNameAttr, extractorDefaultClass);
		config.appendChild(extractor);
		
		
		Element searchAnalyzersElem = configDoc.createElement(searchAnalyzers);
		Element searchAnalyzerDef = configDoc.createElement(analyzer);
		searchAnalyzersElem.appendChild(searchAnalyzerDef);
		searchAnalyzerDef.setAttribute(langAttr, "en");
		searchAnalyzerDef.setAttribute(classNameAttr, StandardAnalyzer.class.getName());
		config.appendChild(searchAnalyzersElem);
		
		Element indexAnalyzersElem = configDoc.createElement(indexAnalyzers); 
		Element analyzerIndexDef = configDoc.createElement(analyzer);
		indexAnalyzersElem.appendChild(analyzerIndexDef);
		analyzerIndexDef.setAttribute(langAttr, "en");
		analyzerIndexDef.setAttribute(classNameAttr, StandardAnalyzer.class.getName());
		config.appendChild(indexAnalyzersElem);
		
		
		Utils.saveDocument(repositoryPath + CONFIG_DOC_PATH, null, configDoc);
		
		return configDoc;
	}
	public void setExtractorClass(String className)
	{
		String xpath = "//extractor";
		List<Node> storageNodes = MainXPath.processXPath(xpath, configDoc.getDocumentElement());
		((Element)storageNodes.get(0)).setAttribute("className", className);
	}
	public void saveConfigDoc() throws Exception
	{
		Utils.saveDocument(repositoryPath + CONFIG_DOC_PATH, null, configDoc);
		
	}
}
